/*
 * ibdcgi.cpp
 *
 *  Created on: Sep 23, 2011
 *      Author: lindenb
 */
#include <cassert>
#include <cerrno>
#include "bdbibd.h"
#include "xstring.h"
#include "cgi.h"
using namespace std;
using namespace bdb;

#define QUOTE(a) "\""<< a << "\""
#define GETENV(a) (getenv(a)==NULL?"":getenv(a))

class ApplicationCGI:public ApplicationReader
	{
	public:
		ApplicationCGI()
			{

			}
		virtual ~ApplicationCGI()
			{

			}
	};

struct CGIApp
	{
	cgistreambuf* buf;
	ApplicationCGI* reader;
	Family* family;
	set<Individual*>* individuals;
	char* remote_user;
	set<string>* http_user_family_restriction;
	};




static void firstForm(CGIApp* app)
	{
	cout << "<html><body>";
	cout << "<h1>Select a Family</h1>";
	cout << "<form action="<<QUOTE(GETENV("REQUEST_URI"))<< ">"
			"<input type='hidden' name='action' value='choose.family'/>"
			"<select name='family'>"
			;
	for(map<family_id_t,Family*>::iterator r=app->reader->env()->id2family.begin();
				r!=app->reader->env()->id2family.end();
				++r)
		{
		if(!app->http_user_family_restriction->empty() &&
			app->http_user_family_restriction->find(r->second->name)==app->http_user_family_restriction->end())
			{
			continue;
			}
		cout << "<option>" << r->second->name << "</option>";
		}
	cout << "</select><br/><input type='submit'/></form></body></html>";
	}

static void secondForm(CGIApp* app)
	{
	cout << "<html><body>";
	cout << "<h1>" << app->family->name << " : Select an Individual</h1>";
	cout << "<form action="<<QUOTE(GETENV("REQUEST_URI"))<< ">"
			"<input type='hidden' name='action' value='choose.individual'/>"
			"<input type='hidden' name='family' value="<< QUOTE(app->family->name)<< "/>"

			;
	for(map<string,Individual*>::iterator r=app->family->name2individual.begin();
				r!=app->family->name2individual.end();
				++r)
		{
		if(!app->http_user_family_restriction->empty() &&
			app->http_user_family_restriction->find(r->second->family->name)==app->http_user_family_restriction->end())
			{
			continue;
			}
		cout << "<input type='checkbox' name='individual' value="<< QUOTE(r->second->name)<< " id='i"<< r->second->id << "'/>"
				"<label for='i"<<  r->second->id << "'>" <<
				r->second->name<<
				"</label><br/>";
		}
	cout << "<input type='submit'/></form></body></html>";
	}

static void thirdForm(CGIApp* app)
	{
	cout << "<html><body>";
	cout << "<h1>" << app->family->name << " : "<< app->individuals->size()<< " Individual(s)</h1>";
	cout << "<form action="<<QUOTE(GETENV("REQUEST_URI"))<< ">"
			"<input type='hidden' name='action' value='get.result'/>"
			"<input type='hidden' name='family' value="<< QUOTE(app->family->name)<< "/>"
			;
	for(set<Individual*>::iterator r=app->individuals->begin();r!=app->individuals->end();++r)
		{
		if(!app->http_user_family_restriction->empty() &&
			app->http_user_family_restriction->find((*r)->family->name)==app->http_user_family_restriction->end())
			{
			continue;
			}
		cout << "<input type='hidden' name='individual' value="<< QUOTE((*r)->name)<< "/>";
		}
	cout << "<h3>Enter rs number</h3><br/>(One rs## per line):<br/><textarea  name='rs' id='rs'></textarea><br/>";
	cout << "<h3>Enter region (chrom:start-end)</h3><br/><input type='text' name='region' id='region'/><br/>";
	cout << "<h3>Parameters</h3>"


		"<input type='radio' name='format' id='fmt1' value='0'/>"
		"<label for='fmt1'>One line per pair</label>"
		"<input type='radio' name='format' id='fmt2' value='1'/>"
		"<label for='fmt2'>All pairs on line</label>"
		"<br/>"
		"<label for='noself'>Don't print slef-self pairs</label>:"
		"<input type='checkbox' name='noself' id='noself' value='true'/>"
		"<br/>"
		;
	cout << "<br/><input type='submit'/></form></body></html>";
	}
#define BDBENV (app->reader->env())


#define GET_FAMILY const char* familyName=cgi.getParameter("family");\
					app.family= reader.env()->findFamilyByName(familyName);\
					if(app.family==NULL) break;\
					if(!http_user_family_restriction.empty() && \
						http_user_family_restriction.find(app.family->name)==http_user_family_restriction.end()) \
						break


#define GET_INDIVIDUALS set<string> indiNames=cgi.getParameters("individual");\
						set<Individual*> individuals;\
						app.individuals=&individuals;\
						for(set<string>::iterator r=indiNames.begin();r!=indiNames.end();++r)\
							{\
							Individual* individual=app.family->findIndividualByName(*r);\
							if(individual==NULL)\
								{\
								individuals.clear();\
								break;\
								}\
							if(!http_user_family_restriction.empty() && \
								http_user_family_restriction.find(individual->family->name)==http_user_family_restriction.end()) \
								{\
								continue;\
								}\
							individuals.insert(individual);\
							}\
						if(individuals.empty())\
							{\
							secondForm(&app);\
							break;\
							}

int main(int argc, char** argv)
	{
	cgistreambuf buf(cout.rdbuf());
	buf.setContentType("text/html");
	cout.rdbuf(&buf);
	ApplicationCGI reader;
	set<string> http_user_family_restriction;
	CGIApp app;
	memset((void*)&app,0,sizeof(CGIApp));
	app.buf=&buf;
	app.reader=&reader;
	app.remote_user=getenv("REMOTE_USER");
	app.http_user_family_restriction=&http_user_family_restriction;
	reader.errstream=NULL;
	reader.output=&cout;

	if(app.remote_user!=NULL)
		{
		//cout << "\"" << app.remote_user << "\"" << endl;
		char* user2fam=::getenv("IBD_RESTRICT_USER_FAMILY");
		if(user2fam!=NULL)
			{
			char* line;
			//cout << "\"" << user2fam << "\"" << endl;
			FILE* rin=fopen(user2fam,"r");
			if(rin==NULL)
				{
				cout << "Cannot open "<< user2fam << " "<< strerror(errno)<< endl;
				return 0;
				}



			StdioReader r(rin);
			while((line=r.readLine())!=NULL)
				{

				if(line [0]=='\0' || line[0]=='#')
					{
					continue;
					}
				char* tab=strchr(line,'\t');
				if(tab==NULL)
					{
					cout << "TAB MISSING IN "<<line << " in "<< user2fam << endl;
					continue;
					}
				if(strncmp(app.remote_user,line,(tab-line))!=0) continue;
				//cout << (tab+1) << endl;
				http_user_family_restriction.insert(tab+1);
				}
			r.close();

			fclose(rin);
			}
		}


	try {
		char* db_home=getenv("DB_HOME");
		if(db_home==NULL) THROW("Undefined $DB_HOME");
		CGI cgi;
		cgi.parse();

		reader.env()->open(db_home,true);
		do
			{
			const char* action=cgi.getParameter("action");
			if(action==NULL)
				{
				firstForm(&app);
				break;
				}
			else if(strcmp(action,"choose.family")==0 &&
					cgi.contains("family"))
				{
				GET_FAMILY;
				secondForm(&app);
				}
			else if(strcmp(action,"choose.individual")==0 &&
					 cgi.contains("family") &&
					 cgi.contains("individual")
					 )
				{
				GET_FAMILY;
				GET_INDIVIDUALS
				thirdForm(&app);
				}
			else if(strcmp(action,"get.result")==0 &&
					 cgi.contains("family") &&
					 cgi.contains("individual")
					 )
				{
				GET_FAMILY;
				GET_INDIVIDUALS

				if(cgi.contains("noself") && strcmp(cgi.getParameter("noself"),"true")==0)
				    {
				    reader.print_self_self=false;
				    }

				if(cgi.contains("format") )
				    {
				    if(strcmp(cgi.getParameter("format"),"0")==0)
						{
						reader.output_mode=ApplicationReader::ONE_PAIR_PER_LINE;
						}
				    else if(strcmp(cgi.getParameter("format"),"1")==0)
						{
						reader.output_mode=ApplicationReader::ALL_PAIRS_ON_LINE;
						}
				    }


				const char* pos=cgi.getParameter("region");
				const char* rs_name=cgi.getParameter("rs");

				reader.restric_family_ids.insert(app.family->id);
				for(set<Individual*>::iterator r=app.individuals->begin();
						r!=app.individuals->end();++r)
					{
					reader.restric_individuals_ids.insert((*r)->id);
					}

				buf.setContentType("text/plain");
				reader.resultHeader1();
				cout.flush();
				buf.pubsync();


				if(pos!=NULL && strlen(pos)>0)
					{

					int tid;
					auto_ptr<GenomicPosition> genomic =GenomicPosition::parse(pos);

					if( genomic.get()!=NULL &&
						(tid=reader.env()->findTidByName(genomic->chromosome.c_str()))!=-1
						)
						{

						reader.scanRegion(genomic.get());
						}//end of genomic !=NULL
					else
						{

						}
					}
				else if(rs_name!=NULL && strlen(rs_name)>0)
					{

					CStringReader strReader(rs_name);
					reader.readRsList(&strReader);
					break;
					}

				}


			} while(false);
		if(!buf.headersFlushed())
			{
			firstForm(&app);
			}
		}
	catch (exception& e)
		{
		buf.setStatus(500);
		cout << "Error:" << e.what() << endl;
		}
	catch(...)
		{
		buf.setStatus(500);
		cout << "An error occured" << endl;
		}


	return 0;
	}
